package com.ruoyi.questionBank.domain;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.ruoyi.common.utils.ObjectUtil;
import com.ruoyi.questionBank.enums.QuestionTypeEnum;
import lombok.Data;
import org.apache.commons.lang3.CharSequenceUtils;
import org.apache.commons.lang3.StringEscapeUtils;

import java.nio.charset.Charset;
import java.util.*;
import java.util.stream.Collectors;

@Data
public class Question {
    /** 选项数据分隔符*/
    public static final String OPTION_SEPARATOR = "\\|";
    /** 多选答案分隔符*/
    public static final String CHECKBOX_SEPARATOR = "&";
    /** 多选答案，用户提交的选项分隔符*/
    public static final String CHECKBOX_USER_ANSWER_SEPARATOR = "&";
    /** 填空答案，用户提交的选项分隔符*/
    public static final String FILL_IN_USER_ANSWER_SEPARATOR = "\\r?\\n";

    private static final char[] OPTION_INDEX = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};

    private Integer id;
    private String content; //问题内容 ,1+1等于几

    private String optionStr;// 选项
    private List<String> option;// 选项

    private String answer; //答案

    private Integer type; //1单选 2多选 3判断 4填空
    private Integer level; //问题难度

    private String analysis; //题目解析

    private Long createPerson; // 创建人uid

    private Long courseNo;
    private Integer bankType;

    private Boolean enable;
    private Integer sort;

    private Date createTime;
    private Date updateTime;

    public void unloadAnswer(){
        this.answer = "";
    }


    /**
     * 检查答案是否匹配选项并重组答案
     */
    public void verifyAndRebuildAnswer(){
        if(type == QuestionTypeEnum.RADIO.getType()
                || type == QuestionTypeEnum.CHECKBOX.getType()
                || type == QuestionTypeEnum.JUDGE.getType()){
            fillOptionIndex();
            if(!answerMatchOption()){
                String[] answerArr = this.answer.split(CHECKBOX_USER_ANSWER_SEPARATOR);
                List<String> opts = getOption();
                List<String> tmp = new ArrayList<>();
                for(int i = 0 ; i < answerArr.length ;i++){
                    char c = answerArr[i].charAt(0);
                    Optional<String> optTmp = opts.stream().filter(opt -> opt.charAt(0) == c)
                            .findFirst();
                    if(optTmp.isPresent()){
                        tmp.add(optTmp.get());
                    }
                }
                if(tmp.isEmpty()){
                    throw new IllegalArgumentException("answer ["+this.answer+"] mismatch option[" + this.optionStr + "]");
                }
                buildAnswer(tmp);
            }
        }else if(type == QuestionTypeEnum.FILL_IN.getType()){
            String[] arr = getAnswer().split(CHECKBOX_SEPARATOR);
            StringBuilder  tmp = new StringBuilder();
            for(String v : arr){
                tmp.append(StrUtil.trimToEmpty(v)).append(StringEscapeUtils.unescapeJava(CHECKBOX_SEPARATOR));
            }
            tmp.deleteCharAt(tmp.lastIndexOf(StringEscapeUtils.unescapeJava(CHECKBOX_SEPARATOR)));
            setAnswer(tmp.toString());
        }
    }

    /**
     * 选项补全前缀下标
     *
     */
    private void fillOptionIndex(){
        List<String> opts = getOption();
        if(opts != null && !opts.isEmpty()) {
            List<String> tmp = new ArrayList<>(opts.size());
            int idx = 0;
            for (String opt : opts) {
                opt = StrUtil.trimToEmpty(opt);
                char c = opt.charAt(0);
                if (!ArrayUtil.contains(OPTION_INDEX, c)) {
                    opt = String.valueOf(OPTION_INDEX[idx]) + ' ' + opt;
                }
                tmp.add(opt);
                idx++;
            }
            setOption(tmp);
        }
    }

    /**
     * 答案是否完全匹配选项
     * @return
     */
    private boolean answerMatchOption(){
        List<String> opts = getOption();
        String[] arr = answer.split(CHECKBOX_SEPARATOR);
        for(String a : arr){
            if(!opts.contains(a)){
                return false;
            }
        }
        return true;
    }

    public void buildAnswer(List<String> option) {
        StringBuilder str = new StringBuilder();
        int len = option.size() - 1;
        for(int i = 0 ; i < len ; i++){
            str.append(option.get(i)).append(StringEscapeUtils.unescapeJava(CHECKBOX_SEPARATOR));
        }
        str.append(option.get(len));
        this.answer = str.toString();
    }


    /**
     * 打乱选项顺序
     */
    public void reorderOption(){
        if(type == QuestionTypeEnum.RADIO.getType() || type == QuestionTypeEnum.CHECKBOX.getType()){
            String[] os = optionStr.split(OPTION_SEPARATOR);
            List<String> idx = new ArrayList<>(os.length);
            for(int i = 0 ; i < os.length ; i++){
                idx.add(os[i]);
            }
            StringBuilder sb = new StringBuilder();
            for(int i = 0 ; i < os.length - 1 ; i++){
                String r = RandomUtil.randomEle(idx);
                idx.remove(r);
                sb.append(r).append(StringEscapeUtils.unescapeJava(OPTION_SEPARATOR));
            }
            sb.append(idx.get(0));
            setOptionStr(sb.toString());
        }
    }

    /**
     * 答案是否正确
     * @param answer
     * @return
     */
    public boolean answerResult(String answer){
        if(answer == null){
            return false;
        }
        if(type == QuestionTypeEnum.CHECKBOX.getType()){
            String[] tmp = answer.split(CHECKBOX_USER_ANSWER_SEPARATOR);
            String[] as =  this.answer.split(CHECKBOX_SEPARATOR);
            for(String a : as){
                boolean has = false;
                for (String t : tmp){
                    if(t.trim().equals(a.trim())){
                        has = true;
                        break;
                    }
                }
                if(!has){
                    return false;
                }
            }
            return true;
        }else {
            if(type == QuestionTypeEnum.FILL_IN.getType()){
                String[] arr = StrUtil.trimToEmpty(answer).split(FILL_IN_USER_ANSWER_SEPARATOR);
                answer = ArrayUtil.join(arr ,StringEscapeUtils.unescapeJava(CHECKBOX_SEPARATOR));
            }
            return this.answer.equals(answer);
        }
    }

    public void setOptionStr(String optionStr) {
        this.optionStr = optionStr;
        String[] arr = optionStr.split(OPTION_SEPARATOR);
        option = Arrays.stream(arr).collect(Collectors.toList());
    }

    public List<String> getOption(){
        if(option == null && !StrUtil.isBlank(optionStr)){
            setOptionStr(optionStr);
        }
        return option;
    }


    public void setOption(List<String> option) {
        this.option = option;
        this.optionStr = CollUtil.join(option ,StringEscapeUtils.unescapeJava(OPTION_SEPARATOR));
    }

    /**
     * 检查考试信息是否完备
     */
    public void verifyComplete(){
        ObjectUtil.checkEmpty(content ,"content");
        if(type != QuestionTypeEnum.FILL_IN.getType()){
            ObjectUtil.checkEmpty(optionStr ,"optionStr");
        }
        ObjectUtil.checkEmpty(answer ,"answer");
        ObjectUtil.checkNull(type ,"type");
        ObjectUtil.checkNull(createPerson ,"createPerson");
    }

    public void setDefault(){
        if(level == null){
            level = 0;
        }
        if(sort == null){
            sort = 0;
        }
        if(analysis == null){
            analysis = "";
        }
        if(optionStr == null && type == QuestionTypeEnum.FILL_IN.getType()){
            optionStr = "";
        }
        if(bankType == null){
            bankType = 0;
        }
        if(courseNo == null){
            courseNo = 0L;
        }
        enable = true;
        createTime = new Date();
        updateTime = createTime;
    }
}
